package cn.wolfcode.wolf2w.service.impl;

import cn.wolfcode.wolf2w.domain.Destination;
import cn.wolfcode.wolf2w.domain.Region;
import cn.wolfcode.wolf2w.query.DestinationQuery;
import cn.wolfcode.wolf2w.repository.DestinationRepository;
import cn.wolfcode.wolf2w.service.IDestinationService;
import cn.wolfcode.wolf2w.service.IRegionService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.*;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;

/**
 * 目的地业务层的实现类
 */
@Service
public class DestinationServiceImpl implements IDestinationService {

    //  注入DestinationRepository持久层接口
    @Autowired
    private DestinationRepository destinationRepository;

    //  注入IRegionService业务层接口
    @Autowired
    private IRegionService regionService;

    //  注入IDestinationService业务层接口
    @Autowired
    private IDestinationService destinationService;

    //  注入MongoTemplate服务
    @Autowired
    private MongoTemplate mongoTemplate;

    //  插入单个方法
    @Override
    public void insert(Destination destination) {

        //  id自动生成，手动设置为空
        destination.setId(null);

        //  调用持久层接口的save方法执行插入单个目的地对象
        destinationRepository.save(destination);
    }

    //  删除单个方法
    @Override
    public void deleteById(String id) {

        //  调用持久层接口的deleteById方法执行删除单个目的地对象
        destinationRepository.deleteById(id);
    }

    //  修改单个方法
    @Override
    public void updateById(Destination destination) {

        //  调用持久层接口的save方法执行修改单个目的地对象
        destinationRepository.save(destination);
    }

    //  修改简介方法
    @Override
    public void updateInfo(Destination destination) {

        //  mongodb的save操作是全量更新，更新单个数据时，其他数据会被清空
        //  因此我们做修改操作时，需要先查询传过来的对象再设置需要修改的参数值

        //  调用本类的查询单个的方法，传入前端的destination对象的id进行查询
        Destination dest = this.selectById(destination.getId());

        //  设置简介内容，获取前端的destination对象的简介内容并传入
        dest.setInfo(destination.getInfo());

        //  调用本类的修改单个的方法，进行修改操作
        this.updateById(dest);
    }

    //  查询单个方法
    @Override
    public Destination selectById(String id) {

        //  调用持久层接口的findById方法执行查询单个目的地对象
        return destinationRepository.findById(id).orElse(null);
    }

    //  查询所有方法
    @Override
    public List<Destination> selectAll() {

        //  调用持久层接口的findAll方法执行查询所有目的地对象
        return destinationRepository.findAll();
    }

    //  查询区域下的所有目的地对象
    @Override
    public List<Destination> queryDestByRegionId(String rid) {

        //  将传过来的rid进行区域对象查询
        Region region = regionService.selectById(rid);

        //  获取单个区域对象的所有目的地对象
        List<String> ids = region.getRefIds();

        //  将集合查询出来并返回
        return destinationRepository.findByIdIn(ids);
    }

    //  分页方法
    @Override
    public Page<Destination> query(DestinationQuery qo) {

        //  查询对象
        Query query = new Query();

        //  判断qo对象中的关键字是否为空且有长度
        if (StringUtils.hasLength(qo.getKeyword())) {

            //  若有长度且不为空，进行模糊查询
            //  把name字段和qo对象中的关键字进行模糊比较
            //  添加到查询对象中
            query.addCriteria(Criteria.where("name").regex(qo.getKeyword()));
        }

        //  判断qo对象中的关键字是否为空且有长度
        if (StringUtils.hasLength(qo.getParentId())) {

            //  若有长度且不为空，进行查询
            //  把parentId字段和qo对象中的关键字进行判断
            //  若有parentId则，添加到查询对象中
            query.addCriteria(Criteria.where("parentId").is(qo.getParentId()));

        } else {

            //  若没有长度或为空，进行查询
            //  把parentId字段和qo对象中的关键字进行判断
            //  若没有parentId则，添加到查询对象中
            query.addCriteria(Criteria.where("parentId").is(null));
        }

        //  调用mongodb服务中的count方法
        //  传入上面的查询对象和Destination的字节码对象
        //  返回一个满足条件的总记录数
        long totalCount = mongoTemplate.count(query, Destination.class);

        //  若查询出来的总记录数为零时
        if (totalCount == 0) {

            //  直接返回一个空集合
            return Page.empty();
        }

        //  调用Pageable的of方法
        //  传入qo对象的当前页，qo对象的当前页显示的最大记录数，排序的顺序，通过_id来排序
        Pageable pageable = PageRequest.of(qo.getCurrentPage()-1, qo.getPageSize(), Sort.Direction.ASC, "_id");

        //  把限制条件加入到查询对象中
        query.with(pageable);

        //  调用mongodb服务中的find方法
        //  传入上面的查询对象和Destination的字节码对象
        //  返回一个满足条件的目的地对象的集合数据
        List<Destination> destinations = mongoTemplate.find(query, Destination.class);

        //  返回一个PageImpl的集合
        //  传入一个满足条件的目的地对象的集合数据对象
        //  传入限制条件
        //  返回一个满足条件的总记录数
        return new PageImpl<>(destinations, pageable, totalCount);
    }

    //  查询子类目的地对象
    @Override
    public List<Destination> queryByParentId(String parentId) {

        //  判断parentId是否为空且为null
        if (!StringUtils.hasLength(parentId)) {

            //  若为空，返回一个空集合
            return Collections.emptyList();
        }

        //  创建一个空集合用来存储destination对象
        List<Destination> list = new ArrayList<>();

        //  通过父级id查询目的地对象
        Destination destination = destinationService.selectById(parentId);

        //  添加到集合中
        list.add(destination);

        //  使用while循环
        while (true) {

            //  判断当前目的地对象是否父级id
            if (destination.getParentId() == null) {

                //  若为空，则跳出循环
                break;

                //  若不为空，则继续循环
            } else {

                //  通过当前目的地对象的父级id查询目的地对象
                destination = destinationService.selectById(destination.getParentId());

                //  添加到集合中
                list.add(destination);
            }
        }

        //  反转集合方法
        Collections.reverse(list);

        //  返回list集合
        return list;
    }


    /*
        @Override
        public List<Destination> queryByParentId(String parentId) {
            List<Destination> list = new ArrayList<>();

            this.createDest(list, parentId);
            Collections.reverse(list);

            return list;
        }

        protected void createDest(List<Destination> list, String parentId){

            if (!StringUtils.hasLength(parentId)) {
                return;
            }

            Destination destination = destinationService.selectById(parentId);
            list.add(destination);

            if (StringUtils.hasLength(destination.getParentId())) {
                createDest(list, destination.getParentId());
            }

        }
    */

    //  通过区域id查询目的地对象
    @Override
    public List<Destination> queryDestByRegionIdApi(String regionId) {

        //  创建一个空集合用来存储目的地对象
        List<Destination> list = new ArrayList<>();

        //  判断regionId是否为-1
        if ("-1".equals(regionId)) {

            //  若为-1
            //  则通过父级name查询所有父级name为"中国"的目的地对象
            List<Destination> listDestination = destinationRepository.findByParentName("中国");

            //  存入集合中
            list = listDestination;

            //  若不为-1
        } else {

            //  判断regionId是否有长度且不为null
            if (StringUtils.hasLength(regionId)) {

                //  若有长度且不为null
                //  通过regionId查询出区域对象
                Region region = regionService.selectById(regionId);

                //  获取区域对象中的目的地对象的id集合
                List<String> refIds = region.getRefIds();

                //  通过目的地对象的id集合查询出所有的目的地对象
                List<Destination> byIdIn = destinationRepository.findByIdIn(refIds);

                //  存入集合中
                list = byIdIn;
            }
        }

        //  循环遍历出list集合中的目的地对象
        for (Destination destination : list) {

            //  截取前五，并按照_id来正序排序
            Pageable pageable = PageRequest.of(0, 5, Sort.Direction.ASC, "_id");

            //  将集合中的目的地对象中的id作为条件
            //  查询父级id相同的子类目的地对象
            //  返回一个拥有相同父级id的子类目的地对象集合
            List<Destination> dest = destinationRepository.findByParentId(destination.getId(), pageable);
                destination.setChildren(dest);
        }

        //  返回list集合
        return list;
    }

    @Override
    public Destination queryName(String keyword) {
        return destinationRepository.findByName(keyword);
    }
}
